package com.tyros.web.support.message;

import com.tyros.common.kit.support.BaseCode;
import com.tyros.web.support.i18n.I18nUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Optional;
import java.util.function.Supplier;

/**
 * @author zhangshuaiyin
 * @date 2022/1/15 21:15
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class R<T> implements Serializable {
    /**
     * 响应码
     */
    private String code;

    /**
     * 响应描述
     */
    private String message;

    /**
     * 响应数据体
     */
    private T data;

    /**
     * 创建响应对象(统一异常处理使用，其他不要调用，后续优化统一异常处理国际化问题)
     *
     * @param code    响应码
     * @param message 响应描述
     * @return 响应对象
     */
    public static <T> R<T> of(String code, String message) {
        return new R<>(code, message, null);
    }

    /**
     * 创建响应对象
     *
     * @param message 响应信息
     * @return 响应对象
     */
    public static <T> R<T> of(BaseCode message) {
        return of(message, null);
    }

    /**
     * 创建响应对象
     *
     * @param message 响应信息
     * @param data    响应对象
     * @return 响应对象
     */
    public static <T> R<T> of(BaseCode message, T data) {
        return new R<>(message.getCode(), Optional.ofNullable(I18nUtils.getMessage(message.getCode())).orElse(message.getMessage()), data);
    }

    public static R<BaseCode> success() {
        return of(BaseMessage.SUCCESS);
    }

    public static <T> R<T> success(T data) {
        return of(BaseMessage.SUCCESS, data);
    }

    public static <T> R<T> error() {
        return error(BaseMessage.SYSTEM_ERROR);
    }

    public static <T> R<T> error(BaseCode code) {
        return of(code);
    }

    public T orNull() {
        return Optional.ofNullable(this.data).filter(d -> BaseMessage.SUCCESS.equals(this.code)).orElse(null);
    }

    public T orDefault(Supplier<T> defaultSupplier) {
        return Optional.ofNullable(this.data).filter(d -> BaseMessage.SUCCESS.equals(this.code)).orElseGet(defaultSupplier);
    }

    public T orThrow() {
        return Optional.ofNullable(this.data).filter(d -> BaseMessage.SUCCESS.equals(this.code)).orElseThrow(() -> new BaseException(this.code, this.message));
    }

    public <X extends BaseException> T orThrow(Supplier<? extends X> exceptionSupplier) {
        return Optional.ofNullable(this.data).filter(d -> BaseMessage.SUCCESS.equals(this.code)).orElseThrow(exceptionSupplier);
    }
}
